diff options
Diffstat (limited to 'src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs')
-rw-r--r-- | src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs new file mode 100644 index 0000000..129a03d --- /dev/null +++ b/src/DotNetOpenAuth.Core/Messaging/ErrorUtilities.cs @@ -0,0 +1,385 @@ +//----------------------------------------------------------------------- +// <copyright file="ErrorUtilities.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Messaging { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Web; + + /// <summary> + /// A collection of error checking and reporting methods. + /// </summary> + [ContractVerification(true)] + [Pure] + internal static class ErrorUtilities { + /// <summary> + /// Wraps an exception in a new <see cref="ProtocolException"/>. + /// </summary> + /// <param name="inner">The inner exception to wrap.</param> + /// <param name="errorMessage">The error message for the outer exception.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <returns>The newly constructed (unthrown) exception.</returns> + [Pure] + internal static Exception Wrap(Exception inner, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Assume(errorMessage != null); + return new ProtocolException(string.Format(CultureInfo.CurrentCulture, errorMessage, args), inner); + } + + /// <summary> + /// Throws an internal error exception. + /// </summary> + /// <param name="errorMessage">The error message.</param> + /// <returns>Nothing. But included here so callers can "throw" this method for C# safety.</returns> + /// <exception cref="InternalErrorException">Always thrown.</exception> + [Pure] + internal static Exception ThrowInternal(string errorMessage) { + // Since internal errors are really bad, take this chance to + // help the developer find the cause by breaking into the + // debugger if one is attached. + if (Debugger.IsAttached) { + Debugger.Break(); + } + + throw new InternalErrorException(errorMessage); + } + + /// <summary> + /// Checks a condition and throws an internal error exception if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <exception cref="InternalErrorException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyInternal(bool condition, string errorMessage) { + Contract.Ensures(condition); + Contract.EnsuresOnThrow<InternalErrorException>(!condition); + if (!condition) { + ThrowInternal(errorMessage); + } + } + + /// <summary> + /// Checks a condition and throws an internal error exception if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <param name="args">The formatting arguments.</param> + /// <exception cref="InternalErrorException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyInternal(bool condition, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<InternalErrorException>(!condition); + Contract.Assume(errorMessage != null); + if (!condition) { + errorMessage = string.Format(CultureInfo.CurrentCulture, errorMessage, args); + throw new InternalErrorException(errorMessage); + } + } + + /// <summary> + /// Checks a condition and throws an <see cref="InvalidOperationException"/> if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <exception cref="InvalidOperationException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyOperation(bool condition, string errorMessage) { + Contract.Ensures(condition); + Contract.EnsuresOnThrow<InvalidOperationException>(!condition); + if (!condition) { + throw new InvalidOperationException(errorMessage); + } + } + + /// <summary> + /// Checks a condition and throws a <see cref="NotSupportedException"/> if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <exception cref="NotSupportedException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifySupported(bool condition, string errorMessage) { + Contract.Ensures(condition); + Contract.EnsuresOnThrow<NotSupportedException>(!condition); + if (!condition) { + throw new NotSupportedException(errorMessage); + } + } + + /// <summary> + /// Checks a condition and throws a <see cref="NotSupportedException"/> if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <param name="args">The string formatting arguments for <paramref name="errorMessage"/>.</param> + /// <exception cref="NotSupportedException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifySupported(bool condition, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<NotSupportedException>(!condition); + Contract.Assume(errorMessage != null); + if (!condition) { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, errorMessage, args)); + } + } + + /// <summary> + /// Checks a condition and throws an <see cref="InvalidOperationException"/> if it evaluates to false. + /// </summary> + /// <param name="condition">The condition to check.</param> + /// <param name="errorMessage">The message to include in the exception, if created.</param> + /// <param name="args">The formatting arguments.</param> + /// <exception cref="InvalidOperationException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyOperation(bool condition, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<InvalidOperationException>(!condition); + Contract.Assume(errorMessage != null); + if (!condition) { + errorMessage = string.Format(CultureInfo.CurrentCulture, errorMessage, args); + throw new InvalidOperationException(errorMessage); + } + } + + /// <summary> + /// Throws a <see cref="HostErrorException"/> if some <paramref name="condition"/> evaluates to false. + /// </summary> + /// <param name="condition">True to do nothing; false to throw the exception.</param> + /// <param name="errorMessage">The error message for the exception.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <exception cref="HostErrorException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyHost(bool condition, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<ProtocolException>(!condition); + Contract.Assume(errorMessage != null); + if (!condition) { + throw new HostErrorException(string.Format(CultureInfo.CurrentCulture, errorMessage, args)); + } + } + + /// <summary> + /// Throws a <see cref="ProtocolException"/> if some <paramref name="condition"/> evaluates to false. + /// </summary> + /// <param name="condition">True to do nothing; false to throw the exception.</param> + /// <param name="faultedMessage">The message being processed that would be responsible for the exception if thrown.</param> + /// <param name="errorMessage">The error message for the exception.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <exception cref="ProtocolException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyProtocol(bool condition, IProtocolMessage faultedMessage, string errorMessage, params object[] args) { + Requires.NotNull(args, "args"); + Requires.NotNull(faultedMessage, "faultedMessage"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<ProtocolException>(!condition); + Contract.Assume(errorMessage != null); + if (!condition) { + throw new ProtocolException(string.Format(CultureInfo.CurrentCulture, errorMessage, args), faultedMessage); + } + } + + /// <summary> + /// Throws a <see cref="ProtocolException"/> if some <paramref name="condition"/> evaluates to false. + /// </summary> + /// <param name="condition">True to do nothing; false to throw the exception.</param> + /// <param name="message">The error message for the exception.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <exception cref="ProtocolException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyProtocol(bool condition, string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<ProtocolException>(!condition); + Contract.Assume(message != null); + if (!condition) { + var exception = new ProtocolException(string.Format(CultureInfo.CurrentCulture, message, args)); + if (Logger.Messaging.IsErrorEnabled) { + Logger.Messaging.Error( + string.Format( + CultureInfo.CurrentCulture, + "Protocol error: {0}{1}{2}", + exception.Message, + Environment.NewLine, + new StackTrace())); + } + throw exception; + } + } + + /// <summary> + /// Throws a <see cref="ProtocolException"/>. + /// </summary> + /// <param name="message">The message to set in the exception.</param> + /// <param name="args">The formatting arguments of the message.</param> + /// <returns> + /// An InternalErrorException, which may be "thrown" by the caller in order + /// to satisfy C# rules to show that code will never be reached, but no value + /// actually is ever returned because this method guarantees to throw. + /// </returns> + /// <exception cref="ProtocolException">Always thrown.</exception> + [Pure] + internal static Exception ThrowProtocol(string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Assume(message != null); + VerifyProtocol(false, message, args); + + // we never reach here, but this allows callers to "throw" this method. + return new InternalErrorException(); + } + + /// <summary> + /// Throws a <see cref="FormatException"/>. + /// </summary> + /// <param name="message">The message for the exception.</param> + /// <param name="args">The string formatting arguments for <paramref name="message"/>.</param> + /// <returns>Nothing. It's just here so the caller can throw this method for C# compilation check.</returns> + [Pure] + internal static Exception ThrowFormat(string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Assume(message != null); + throw new FormatException(string.Format(CultureInfo.CurrentCulture, message, args)); + } + + /// <summary> + /// Throws a <see cref="FormatException"/> if some condition is false. + /// </summary> + /// <param name="condition">The expression to evaluate. A value of <c>false</c> will cause the exception to be thrown.</param> + /// <param name="message">The message for the exception.</param> + /// <param name="args">The string formatting arguments for <paramref name="message"/>.</param> + /// <exception cref="FormatException">Thrown when <paramref name="condition"/> is <c>false</c>.</exception> + [Pure] + internal static void VerifyFormat(bool condition, string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<FormatException>(!condition); + Contract.Assume(message != null); + if (!condition) { + throw ThrowFormat(message, args); + } + } + + /// <summary> + /// Verifies something about the argument supplied to a method. + /// </summary> + /// <param name="condition">The condition that must evaluate to true to avoid an exception.</param> + /// <param name="message">The message to use in the exception if the condition is false.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <exception cref="ArgumentException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyArgument(bool condition, string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<ArgumentException>(!condition); + Contract.Assume(message != null); + if (!condition) { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, message, args)); + } + } + + /// <summary> + /// Throws an <see cref="ArgumentException"/>. + /// </summary> + /// <param name="parameterName">Name of the parameter.</param> + /// <param name="message">The message to use in the exception if the condition is false.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <returns>Never returns anything. It always throws.</returns> + [Pure] + internal static Exception ThrowArgumentNamed(string parameterName, string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Assume(message != null); + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, message, args), parameterName); + } + + /// <summary> + /// Verifies something about the argument supplied to a method. + /// </summary> + /// <param name="condition">The condition that must evaluate to true to avoid an exception.</param> + /// <param name="parameterName">Name of the parameter.</param> + /// <param name="message">The message to use in the exception if the condition is false.</param> + /// <param name="args">The string formatting arguments, if any.</param> + /// <exception cref="ArgumentException">Thrown if <paramref name="condition"/> evaluates to <c>false</c>.</exception> + [Pure] + internal static void VerifyArgumentNamed(bool condition, string parameterName, string message, params object[] args) { + Requires.NotNull(args, "args"); + Contract.Ensures(condition); + Contract.EnsuresOnThrow<ArgumentException>(!condition); + Contract.Assume(message != null); + if (!condition) { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, message, args), parameterName); + } + } + + /// <summary> + /// Verifies that some given value is not null. + /// </summary> + /// <param name="value">The value to check.</param> + /// <param name="paramName">Name of the parameter, which will be used in the <see cref="ArgumentException"/>, if thrown.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> + [Pure] + internal static void VerifyArgumentNotNull(object value, string paramName) { + Contract.Ensures(value != null); + Contract.EnsuresOnThrow<ArgumentNullException>(value == null); + if (value == null) { + throw new ArgumentNullException(paramName); + } + } + + /// <summary> + /// Verifies that some string is not null and has non-zero length. + /// </summary> + /// <param name="value">The value to check.</param> + /// <param name="paramName">Name of the parameter, which will be used in the <see cref="ArgumentException"/>, if thrown.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> + /// <exception cref="ArgumentException">Thrown if <paramref name="value"/> has zero length.</exception> + [Pure] + internal static void VerifyNonZeroLength(string value, string paramName) { + Contract.Ensures((value != null && value.Length > 0) && !string.IsNullOrEmpty(value)); + Contract.EnsuresOnThrow<ArgumentException>(value == null || value.Length == 0); + VerifyArgumentNotNull(value, paramName); + if (value.Length == 0) { + throw new ArgumentException(MessagingStrings.UnexpectedEmptyString, paramName); + } + } + + /// <summary> + /// Verifies that <see cref="HttpContext.Current"/> != <c>null</c>. + /// </summary> + /// <exception cref="InvalidOperationException">Thrown if <see cref="HttpContext.Current"/> == <c>null</c></exception> + [Pure] + internal static void VerifyHttpContext() { + Contract.Ensures(HttpContext.Current != null); + Contract.Ensures(HttpContext.Current.Request != null); + ErrorUtilities.VerifyOperation(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); + } + + /// <summary> + /// Obtains a value from the dictionary if possible, or throws a <see cref="ProtocolException"/> if it's missing. + /// </summary> + /// <typeparam name="TKey">The type of key in the dictionary.</typeparam> + /// <typeparam name="TValue">The type of value in the dictionary.</typeparam> + /// <param name="dictionary">The dictionary.</param> + /// <param name="key">The key to use to look up the value.</param> + /// <param name="message">The message to claim is invalid if the key cannot be found.</param> + /// <returns>The value for the given key.</returns> + [Pure] + internal static TValue GetValueOrThrow<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, IMessage message) { + Requires.NotNull(dictionary, "dictionary"); + Requires.NotNull(message, "message"); + + TValue value; + VerifyProtocol(dictionary.TryGetValue(key, out value), MessagingStrings.ExpectedParameterWasMissing, key, message.GetType().Name); + return value; + } + } +} |