//-----------------------------------------------------------------------
//
// Copyright (c) Outercurve Foundation. All rights reserved.
//
//-----------------------------------------------------------------------
namespace DotNetOpenAuth {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
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";
///
/// The web.config file-specified provider of web resource URLs.
///
private static IEmbeddedResourceRetrieval embeddedResourceRetrieval = MessagingElement.Configuration.EmbeddedResourceRetrievalProvider.CreateInstance(null, false, null);
///
/// 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);
}
///
/// 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 })));
}
}
///
/// Validates that a URL will be resolvable at runtime.
///
/// The page hosting the control that receives this URL as a property.
/// If set to true the page is in design-time mode rather than runtime mode.
/// The URI to check.
/// Thrown if the given URL is not a valid, resolvable URI.
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Uri", Justification = "Just to throw an exception on invalid input.")]
internal static void ValidateResolvableUrl(Page page, bool designMode, string value) {
if (string.IsNullOrEmpty(value)) {
return;
}
if (page != null && !designMode) {
Assumes.True(page.Request != null);
// Validate new value by trying to construct a Realm object based on it.
string relativeUrl = page.ResolveUrl(value);
Assumes.True(page.Request.Url != null);
Assumes.True(relativeUrl != null);
new Uri(page.Request.Url, relativeUrl); // throws an exception on failure.
} else {
// We can't fully test it, but it should start with either ~/ or a protocol.
if (Regex.IsMatch(value, @"^https?://")) {
new Uri(value); // make sure it's fully-qualified, but ignore wildcards
} else if (value.StartsWith("~/", StringComparison.Ordinal)) {
// this is valid too
} else {
throw new UriFormatException();
}
}
}
///
/// 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);
}
}
}