//----------------------------------------------------------------------- // // Copyright (c) Outercurve Foundation. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth { using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Net.Http.Headers; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.UI; using DotNetOpenAuth.Configuration; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Reflection; using Validation; /// /// A grab-bag utility class. /// internal static class Util { /// /// The base namespace for this library from which all other namespaces derive. /// internal const string DefaultNamespace = "DotNetOpenAuth"; /// /// A lazily-assembled string that describes the version of the library. /// private static readonly Lazy libraryVersionLazy = new Lazy(delegate { var assembly = Assembly.GetExecutingAssembly(); string assemblyFullName = assembly.FullName; bool official = assemblyFullName.Contains("PublicKeyToken=d0acff3d13b42a9d"); assemblyFullName = assemblyFullName.Replace(assembly.GetName().Version.ToString(), AssemblyFileVersion); // We use InvariantCulture since this is used for logging. return string.Format(CultureInfo.InvariantCulture, "{0} ({1})", assemblyFullName, official ? "official" : "private"); }); /// /// A lazily-assembled string that describes the version of the library. /// private static readonly Lazy libraryVersionHeaderLazy = new Lazy(delegate { var assemblyName = Assembly.GetExecutingAssembly().GetName(); return new ProductInfoHeaderValue(assemblyName.Name, AssemblyFileVersion); }); /// /// The web.config file-specified provider of web resource URLs. /// private static IEmbeddedResourceRetrieval embeddedResourceRetrieval = MessagingElement.Configuration.EmbeddedResourceRetrievalProvider.CreateInstance(null, false, null); /// /// Gets a human-readable description of the library name and version, including /// whether the build is an official or private one. /// internal static string LibraryVersion { get { return libraryVersionLazy.Value; } } /// /// Gets an HTTP header that can be included in outbound requests. /// internal static ProductInfoHeaderValue LibraryVersionHeader { get { return libraryVersionHeaderLazy.Value; } } /// /// Gets the assembly file version of the executing assembly, otherwise falls back to the assembly version. /// internal static string AssemblyFileVersion { get { var assembly = Assembly.GetExecutingAssembly(); var attributes = assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false); if (attributes.Length == 1) { var fileVersionAttribute = (AssemblyFileVersionAttribute)attributes[0]; return fileVersionAttribute.Version; } return assembly.GetName().Version.ToString(); } } /// /// Tests for equality between two objects. Safely handles the case where one or both are null. /// /// The type of objects been checked for equality. /// The first object. /// The second object. /// true if the two objects are equal; false otherwise. internal static bool EqualsNullSafe(this T first, T second) where T : class { // If one is null and the other is not... if (object.ReferenceEquals(first, null) ^ object.ReferenceEquals(second, null)) { return false; } // If both are null... (we only check one because we already know both are either null or non-null) if (object.ReferenceEquals(first, null)) { return true; } // Neither are null. Delegate to the Equals method. return first.Equals(second); } /// /// Prepares a dictionary for printing as a string. /// /// The type of the key. /// The type of the value. /// The dictionary or sequence of name-value pairs. /// An object whose ToString method will perform the actual work of generating the string. /// /// The work isn't done until (and if) the /// method is actually called, which makes it great /// for logging complex objects without being in a conditional block. /// internal static object ToStringDeferred(this IEnumerable> pairs) { return new DelayedToString>>( pairs, p => { Requires.NotNull(pairs, "pairs"); var dictionary = pairs as IDictionary; var messageDictionary = pairs as MessageDictionary; StringBuilder sb = new StringBuilder(dictionary != null ? dictionary.Count * 40 : 200); foreach (var pair in pairs) { var key = pair.Key.ToString(); string value = pair.Value.ToString(); if (messageDictionary != null && messageDictionary.Description.Mapping.ContainsKey(key) && messageDictionary.Description.Mapping[key].IsSecuritySensitive) { value = "********"; } sb.AppendFormat("\t{0}: {1}{2}", key, value, Environment.NewLine); } return sb.ToString(); }); } /// /// Offers deferred ToString processing for a list of elements, that are assumed /// to generate just a single-line string. /// /// The type of elements contained in the list. /// The list of elements. /// An object whose ToString method will perform the actual work of generating the string. internal static object ToStringDeferred(this IEnumerable list) { return ToStringDeferred(list, false); } /// /// Offers deferred ToString processing for a list of elements. /// /// The type of elements contained in the list. /// The list of elements. /// if set to true, special formatting will be applied to the output to make it clear where one element ends and the next begins. /// An object whose ToString method will perform the actual work of generating the string. internal static object ToStringDeferred(this IEnumerable list, bool multiLineElements) { return new DelayedToString>( list, l => { // Code contracts not allowed in generator methods. ErrorUtilities.VerifyArgumentNotNull(l, "l"); string newLine = Environment.NewLine; ////Assumes.True(newLine != null && newLine.Length > 0); StringBuilder sb = new StringBuilder(); if (multiLineElements) { sb.AppendLine("[{"); foreach (T obj in l) { // Prepare the string repersentation of the object string objString = obj != null ? obj.ToString() : ""; // Indent every line printed objString = objString.Replace(newLine, Environment.NewLine + "\t"); sb.Append("\t"); sb.Append(objString); if (!objString.EndsWith(Environment.NewLine, StringComparison.Ordinal)) { sb.AppendLine(); } sb.AppendLine("}, {"); } if (sb.Length > 2 + Environment.NewLine.Length) { // if anything was in the enumeration sb.Length -= 2 + Environment.NewLine.Length; // trim off the last ", {\r\n" } else { sb.Length -= 1 + Environment.NewLine.Length; // trim off the opening { } sb.Append("]"); return sb.ToString(); } else { sb.Append("{"); foreach (T obj in l) { sb.Append(obj != null ? obj.ToString() : ""); sb.AppendLine(","); } if (sb.Length > 1) { sb.Length -= 1; } sb.Append("}"); return sb.ToString(); } }); } /// /// Gets the web resource URL from a Page or object. /// /// Some type in resource assembly. /// Name of the manifest resource. /// An absolute URL internal static string GetWebResourceUrl(Type someTypeInResourceAssembly, string manifestResourceName) { Page page; IEmbeddedResourceRetrieval retrieval; if (embeddedResourceRetrieval != null) { Uri url = embeddedResourceRetrieval.GetWebResourceUrl(someTypeInResourceAssembly, manifestResourceName); return url != null ? url.AbsoluteUri : null; } else if ((page = HttpContext.Current.CurrentHandler as Page) != null) { return page.ClientScript.GetWebResourceUrl(someTypeInResourceAssembly, manifestResourceName); } else if ((retrieval = HttpContext.Current.CurrentHandler as IEmbeddedResourceRetrieval) != null) { return retrieval.GetWebResourceUrl(someTypeInResourceAssembly, manifestResourceName).AbsoluteUri; } else { throw new InvalidOperationException( string.Format( CultureInfo.CurrentCulture, Strings.EmbeddedResourceUrlProviderRequired, string.Join(", ", new string[] { typeof(Page).FullName, typeof(IEmbeddedResourceRetrieval).FullName }))); } } /// /// Creates a dictionary of a sequence of elements and the result of an asynchronous transform, /// allowing the async work to proceed concurrently. /// /// The type of the source. /// The type of the result. /// The source. /// The transform. /// A dictionary populated with the results of the transforms. internal static async Task> ToDictionaryAsync( this IEnumerable source, Func> transform) { var taskResults = source.ToDictionary(s => s, transform); await Task.WhenAll(taskResults.Values); return taskResults.ToDictionary(p => p.Key, p => p.Value.Result); } /// /// Manages an individual deferred ToString call. /// /// The type of object to be serialized as a string. private class DelayedToString { /// /// The object that will be serialized if called upon. /// private readonly T obj; /// /// The method used to serialize to string form. /// private readonly Func toString; /// /// Initializes a new instance of the DelayedToString class. /// /// The object that may be serialized to string form. /// The method that will serialize the object if called upon. public DelayedToString(T obj, Func toString) { Requires.NotNull(toString, "toString"); this.obj = obj; this.toString = toString; } /// /// Returns a that represents the current . /// /// /// A that represents the current . /// public override string ToString() { return this.toString(this.obj) ?? string.Empty; } } } }