//-----------------------------------------------------------------------
//
// 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;
}
}
}
}