mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: aa7f0039e40c8e105e02d2c8748c1c6bc54edcec Former-commit-id: 54f50e77d563990dacacac41293caf26e72d3014 Former-commit-id: a7ca5b704017245ce4f4a19bd4904f150b4783a1pull/17/head
32 changed files with 1573 additions and 668 deletions
@ -0,0 +1,210 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="ExtendedColorTypeConverter.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// The extended color type converter allows conversion of system and web colors.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Web.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.ComponentModel; |
||||
|
using System.Drawing; |
||||
|
using System.Globalization; |
||||
|
using System.Text; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The extended color type converter allows conversion of system and web colors.
|
||||
|
/// </summary>
|
||||
|
public class ExtendedColorTypeConverter : ColorConverter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The web color regex.
|
||||
|
/// </summary>
|
||||
|
private static readonly Regex WebColorRegex = new Regex("([0-9a-fA-F]{3}){1,2}", RegexOptions.Compiled); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The html system color table map.
|
||||
|
/// </summary>
|
||||
|
private static Hashtable htmlSystemColorTable; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the given object to the type of this converter, using the specified context and culture
|
||||
|
/// information.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// An <see cref="T:System.Object"/> that represents the converted value.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">The <see cref="T:System.Object"/> to convert. </param>
|
||||
|
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed.</exception>
|
||||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
string s = value as string; |
||||
|
if (s != null) |
||||
|
{ |
||||
|
string colorText = s.Trim(); |
||||
|
Color c = Color.Empty; |
||||
|
|
||||
|
// Empty color
|
||||
|
if (string.IsNullOrEmpty(colorText)) |
||||
|
{ |
||||
|
return c; |
||||
|
} |
||||
|
|
||||
|
// Special case. HTML requires LightGrey, but System.Drawing.KnownColor has LightGray
|
||||
|
if (colorText.Equals("LightGrey", StringComparison.OrdinalIgnoreCase)) |
||||
|
{ |
||||
|
return Color.LightGray; |
||||
|
} |
||||
|
|
||||
|
// Hex based color values.
|
||||
|
char hash = colorText[0]; |
||||
|
if (hash == '#' || WebColorRegex.IsMatch(colorText)) |
||||
|
{ |
||||
|
if (hash != '#') |
||||
|
{ |
||||
|
colorText = "#" + colorText; |
||||
|
} |
||||
|
|
||||
|
if (colorText.Length == 7) |
||||
|
{ |
||||
|
return Color.FromArgb( |
||||
|
Convert.ToInt32(colorText.Substring(1, 2), 16), |
||||
|
Convert.ToInt32(colorText.Substring(3, 2), 16), |
||||
|
Convert.ToInt32(colorText.Substring(5, 2), 16)); |
||||
|
} |
||||
|
|
||||
|
// Length is 4
|
||||
|
string r = char.ToString(colorText[1]); |
||||
|
string g = char.ToString(colorText[2]); |
||||
|
string b = char.ToString(colorText[3]); |
||||
|
|
||||
|
return Color.FromArgb( |
||||
|
Convert.ToInt32(r + r, 16), |
||||
|
Convert.ToInt32(g + g, 16), |
||||
|
Convert.ToInt32(b + b, 16)); |
||||
|
} |
||||
|
|
||||
|
// System color
|
||||
|
if (htmlSystemColorTable == null) |
||||
|
{ |
||||
|
InitializeHtmlSystemColorTable(); |
||||
|
} |
||||
|
|
||||
|
if (htmlSystemColorTable != null) |
||||
|
{ |
||||
|
object o = htmlSystemColorTable[colorText]; |
||||
|
if (o != null) |
||||
|
{ |
||||
|
return (Color)o; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ColorConverter handles all named and KnownColors
|
||||
|
return base.ConvertFrom(context, culture, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the given value object to the specified type, using the specified context and culture
|
||||
|
/// information.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// An <see cref="T:System.Object"/> that represents the converted value.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// A <see cref="T:System.Globalization.CultureInfo"/>. If null is passed, the current culture is assumed.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">The <see cref="T:System.Object"/> to convert. </param>
|
||||
|
/// <param name="destinationType">
|
||||
|
/// The <see cref="T:System.Type"/> to convert the <paramref name="value"/> parameter to.
|
||||
|
/// </param>
|
||||
|
/// <exception cref="T:System.ArgumentNullException">
|
||||
|
/// The <paramref name="destinationType"/> parameter is null.
|
||||
|
/// </exception>
|
||||
|
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed.
|
||||
|
/// </exception>
|
||||
|
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
if (destinationType == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException("destinationType"); |
||||
|
} |
||||
|
|
||||
|
if (destinationType == typeof(string)) |
||||
|
{ |
||||
|
if (value != null) |
||||
|
{ |
||||
|
Color color = (Color)value; |
||||
|
|
||||
|
if (color == Color.Empty) |
||||
|
{ |
||||
|
return string.Empty; |
||||
|
} |
||||
|
|
||||
|
if (color.IsKnownColor == false) |
||||
|
{ |
||||
|
// In the Web scenario, colors should be formatted in #RRGGBB notation
|
||||
|
StringBuilder sb = new StringBuilder("#", 7); |
||||
|
sb.Append(color.R.ToString("X2", CultureInfo.InvariantCulture)); |
||||
|
sb.Append(color.G.ToString("X2", CultureInfo.InvariantCulture)); |
||||
|
sb.Append(color.B.ToString("X2", CultureInfo.InvariantCulture)); |
||||
|
return sb.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return base.ConvertTo(context, culture, value, destinationType); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes color table mapping system colors to known colors.
|
||||
|
/// </summary>
|
||||
|
private static void InitializeHtmlSystemColorTable() |
||||
|
{ |
||||
|
Hashtable hashTable = new Hashtable(StringComparer.OrdinalIgnoreCase); |
||||
|
hashTable["activeborder"] = Color.FromKnownColor(KnownColor.ActiveBorder); |
||||
|
hashTable["activecaption"] = Color.FromKnownColor(KnownColor.ActiveCaption); |
||||
|
hashTable["appworkspace"] = Color.FromKnownColor(KnownColor.AppWorkspace); |
||||
|
hashTable["background"] = Color.FromKnownColor(KnownColor.Desktop); |
||||
|
hashTable["buttonface"] = Color.FromKnownColor(KnownColor.Control); |
||||
|
hashTable["buttonhighlight"] = Color.FromKnownColor(KnownColor.ControlLightLight); |
||||
|
hashTable["buttonshadow"] = Color.FromKnownColor(KnownColor.ControlDark); |
||||
|
hashTable["buttontext"] = Color.FromKnownColor(KnownColor.ControlText); |
||||
|
hashTable["captiontext"] = Color.FromKnownColor(KnownColor.ActiveCaptionText); |
||||
|
hashTable["graytext"] = Color.FromKnownColor(KnownColor.GrayText); |
||||
|
hashTable["highlight"] = Color.FromKnownColor(KnownColor.Highlight); |
||||
|
hashTable["highlighttext"] = Color.FromKnownColor(KnownColor.HighlightText); |
||||
|
hashTable["inactiveborder"] = Color.FromKnownColor(KnownColor.InactiveBorder); |
||||
|
hashTable["inactivecaption"] = Color.FromKnownColor(KnownColor.InactiveCaption); |
||||
|
hashTable["inactivecaptiontext"] = Color.FromKnownColor(KnownColor.InactiveCaptionText); |
||||
|
hashTable["infobackground"] = Color.FromKnownColor(KnownColor.Info); |
||||
|
hashTable["infotext"] = Color.FromKnownColor(KnownColor.InfoText); |
||||
|
hashTable["menu"] = Color.FromKnownColor(KnownColor.Menu); |
||||
|
hashTable["menutext"] = Color.FromKnownColor(KnownColor.MenuText); |
||||
|
hashTable["scrollbar"] = Color.FromKnownColor(KnownColor.ScrollBar); |
||||
|
hashTable["threeddarkshadow"] = Color.FromKnownColor(KnownColor.ControlDarkDark); |
||||
|
hashTable["threedface"] = Color.FromKnownColor(KnownColor.Control); |
||||
|
hashTable["threedhighlight"] = Color.FromKnownColor(KnownColor.ControlLight); |
||||
|
hashTable["threedlightshadow"] = Color.FromKnownColor(KnownColor.ControlLightLight); |
||||
|
hashTable["window"] = Color.FromKnownColor(KnownColor.Window); |
||||
|
hashTable["windowframe"] = Color.FromKnownColor(KnownColor.WindowFrame); |
||||
|
hashTable["windowtext"] = Color.FromKnownColor(KnownColor.WindowText); |
||||
|
htmlSystemColorTable = hashTable; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="GenericArrayTypeConverter.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// Converts the value of an string to and from a Array{T}.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Web.Helpers |
||||
|
{ |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the value of an string to and from a Array{T}.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">
|
||||
|
/// The type to convert from.
|
||||
|
/// </typeparam>
|
||||
|
public class GenericArrayTypeConverter<T> : GenericListTypeConverter<T> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Converts the given object to the type of this converter, using the specified context and culture
|
||||
|
/// information.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// An <see cref="T:System.Object"/> that represents the converted value.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">The <see cref="T:System.Object"/> to convert. </param>
|
||||
|
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed.</exception>
|
||||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
object result = base.ConvertFrom(context, culture, value); |
||||
|
IList<T> list = result as IList<T>; |
||||
|
return list != null ? list.ToArray() : result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,161 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="GenericListTypeConverter.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// Converts the value of an string to and from a List{T}.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Web.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the value of an string to and from a List{T}.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">
|
||||
|
/// The type to convert from.
|
||||
|
/// </typeparam>
|
||||
|
public class GenericListTypeConverter<T> : TypeConverter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The type converter.
|
||||
|
/// </summary>
|
||||
|
private readonly TypeConverter typeConverter; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="GenericListTypeConverter{T}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <exception cref="InvalidOperationException">
|
||||
|
/// Thrown if no converter exists for the given type.
|
||||
|
/// </exception>
|
||||
|
public GenericListTypeConverter() |
||||
|
{ |
||||
|
Type type = typeof(T); |
||||
|
this.typeConverter = TypeDescriptor.GetConverter(type); |
||||
|
if (this.typeConverter == null) |
||||
|
{ |
||||
|
throw new InvalidOperationException("No type converter exists for type " + type.FullName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns whether this converter can convert an object of the given type to the type of this converter,
|
||||
|
/// using the specified context.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// true if this converter can perform the conversion; otherwise, false.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a
|
||||
|
/// format context. </param>
|
||||
|
/// <param name="sourceType">
|
||||
|
/// A <see cref="T:System.Type"/> that represents the type you want to convert from.
|
||||
|
/// </param>
|
||||
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
||||
|
{ |
||||
|
if (sourceType == typeof(string)) |
||||
|
{ |
||||
|
string[] items = this.GetStringArray(sourceType.ToString()); |
||||
|
return items.Any(); |
||||
|
} |
||||
|
|
||||
|
return base.CanConvertFrom(context, sourceType); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the given object to the type of this converter, using the specified context and culture
|
||||
|
/// information.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// An <see cref="T:System.Object"/> that represents the converted value.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">The <see cref="T:System.Object"/> to convert. </param>
|
||||
|
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed.</exception>
|
||||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
string input = value as string; |
||||
|
if (input != null) |
||||
|
{ |
||||
|
string[] items = this.GetStringArray(input); |
||||
|
|
||||
|
List<T> result = new List<T>(); |
||||
|
|
||||
|
Array.ForEach( |
||||
|
items, |
||||
|
s => |
||||
|
{ |
||||
|
object item = this.typeConverter.ConvertFromInvariantString(s); |
||||
|
if (item != null) |
||||
|
{ |
||||
|
result.Add((T)item); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
return base.ConvertFrom(context, culture, value); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts the given value object to the specified type, using the specified context and culture
|
||||
|
/// information.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// An <see cref="T:System.Object"/> that represents the converted value.
|
||||
|
/// </returns>
|
||||
|
/// <param name="context">
|
||||
|
/// An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// A <see cref="T:System.Globalization.CultureInfo"/>. If null is passed, the current culture is assumed.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">The <see cref="T:System.Object"/> to convert. </param>
|
||||
|
/// <param name="destinationType">
|
||||
|
/// The <see cref="T:System.Type"/> to convert the <paramref name="value"/> parameter to.
|
||||
|
/// </param>
|
||||
|
/// <exception cref="T:System.ArgumentNullException">
|
||||
|
/// The <paramref name="destinationType"/> parameter is null.
|
||||
|
/// </exception>
|
||||
|
/// <exception cref="T:System.NotSupportedException">The conversion cannot be performed.
|
||||
|
/// </exception>
|
||||
|
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
if (destinationType == typeof(string)) |
||||
|
{ |
||||
|
return string.Join(",", (IList<T>)value); |
||||
|
} |
||||
|
|
||||
|
return base.ConvertTo(context, culture, value, destinationType); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Splits a string by comma to return an array of string values.
|
||||
|
/// </summary>
|
||||
|
/// <param name="input">
|
||||
|
/// The input string to split.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="string"/> array from the comma separated values.
|
||||
|
/// </returns>
|
||||
|
protected string[] GetStringArray(string input) |
||||
|
{ |
||||
|
string[] result = input.Split(',').Select(s => s.Trim()).ToArray(); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,220 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="QueryParamParser.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// The query parameter parser that converts string values to different types.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Web.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Drawing; |
||||
|
using System.Globalization; |
||||
|
using System.Linq.Expressions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The query parameter parser that converts string values to different types.
|
||||
|
/// </summary>
|
||||
|
public class QueryParamParser |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A new instance of the <see cref="QueryParamParser"/> class.
|
||||
|
/// with lazy initialization.
|
||||
|
/// </summary>
|
||||
|
private static readonly Lazy<QueryParamParser> Lazy = new Lazy<QueryParamParser>(() => new QueryParamParser()); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The cache for storing created default types.
|
||||
|
/// </summary>
|
||||
|
private static readonly ConcurrentDictionary<Type, object> TypeDefaultsCache = new ConcurrentDictionary<Type, object>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Prevents a default instance of the <see cref="QueryParamParser"/> class from being created.
|
||||
|
/// </summary>
|
||||
|
private QueryParamParser() |
||||
|
{ |
||||
|
this.AddColorConverters(); |
||||
|
this.AddListConverters(); |
||||
|
this.AddArrayConverters(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the current <see cref="QueryParamParser"/> instance.
|
||||
|
/// </summary>
|
||||
|
public static QueryParamParser Instance |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return Lazy.Value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Parses the given string value converting it to the given type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">
|
||||
|
/// The <see cref="String"/> value to parse.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// The <see cref="CultureInfo"/> to use as the current culture.
|
||||
|
/// <remarks>If not set will parse using <see cref="CultureInfo.InvariantCulture"/></remarks>
|
||||
|
/// </param>
|
||||
|
/// <typeparam name="T">
|
||||
|
/// The <see cref="Type"/> to convert the string to.
|
||||
|
/// </typeparam>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="T"/>.
|
||||
|
/// </returns>
|
||||
|
public T ParseValue<T>(string value, CultureInfo culture = null) |
||||
|
{ |
||||
|
return (T)this.ParseValue(typeof(T), value, culture); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Parses the given string value converting it to the given type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">
|
||||
|
/// The <see cref="Type"/> to convert the string to.
|
||||
|
/// </param>
|
||||
|
/// <param name="value">
|
||||
|
/// The <see cref="String"/> value to parse.
|
||||
|
/// </param>
|
||||
|
/// <param name="culture">
|
||||
|
/// The <see cref="CultureInfo"/> to use as the current culture.
|
||||
|
/// <remarks>If not set will parse using <see cref="CultureInfo.InvariantCulture"/></remarks>
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="object"/>.
|
||||
|
/// </returns>
|
||||
|
public object ParseValue(Type type, string value, CultureInfo culture = null) |
||||
|
{ |
||||
|
if (culture == null) |
||||
|
{ |
||||
|
culture = CultureInfo.InvariantCulture; |
||||
|
} |
||||
|
|
||||
|
TypeConverter converter = TypeDescriptor.GetConverter(type); |
||||
|
try |
||||
|
{ |
||||
|
// ReSharper disable once AssignNullToNotNullAttribute
|
||||
|
return converter.ConvertFrom(null, culture, value); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
// Return the default value
|
||||
|
return TypeDefaultsCache.GetOrAdd(type, t => this.GetDefaultValue(type)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds a type converter to the parser.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">
|
||||
|
/// The <see cref="Type"/> to add a converter for.
|
||||
|
/// </param>
|
||||
|
/// <param name="converterType">
|
||||
|
/// The type of <see cref="TypeConverter"/> to add.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="TypeDescriptionProvider"/>.
|
||||
|
/// </returns>
|
||||
|
public TypeDescriptionProvider AddTypeConverter(Type type, Type converterType) |
||||
|
{ |
||||
|
return TypeDescriptor.AddAttributes(type, new TypeConverterAttribute(converterType)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds color converters.
|
||||
|
/// </summary>
|
||||
|
private void AddColorConverters() |
||||
|
{ |
||||
|
this.AddTypeConverter(typeof(Color), typeof(ExtendedColorTypeConverter)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds a selection of default list type converters.
|
||||
|
/// </summary>
|
||||
|
private void AddListConverters() |
||||
|
{ |
||||
|
this.AddTypeConverter(typeof(List<sbyte>), typeof(GenericListTypeConverter<sbyte>)); |
||||
|
this.AddTypeConverter(typeof(List<byte>), typeof(GenericListTypeConverter<byte>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(List<short>), typeof(GenericListTypeConverter<short>)); |
||||
|
this.AddTypeConverter(typeof(List<ushort>), typeof(GenericListTypeConverter<ushort>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(List<int>), typeof(GenericListTypeConverter<int>)); |
||||
|
this.AddTypeConverter(typeof(List<uint>), typeof(GenericListTypeConverter<uint>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(List<long>), typeof(GenericListTypeConverter<long>)); |
||||
|
this.AddTypeConverter(typeof(List<ulong>), typeof(GenericListTypeConverter<ulong>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(List<decimal>), typeof(GenericListTypeConverter<decimal>)); |
||||
|
this.AddTypeConverter(typeof(List<float>), typeof(GenericListTypeConverter<float>)); |
||||
|
this.AddTypeConverter(typeof(List<double>), typeof(GenericListTypeConverter<double>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(List<string>), typeof(GenericListTypeConverter<string>)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds a selection of default array type converters.
|
||||
|
/// </summary>
|
||||
|
private void AddArrayConverters() |
||||
|
{ |
||||
|
this.AddTypeConverter(typeof(sbyte[]), typeof(GenericArrayTypeConverter<sbyte>)); |
||||
|
this.AddTypeConverter(typeof(byte[]), typeof(GenericArrayTypeConverter<byte>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(short[]), typeof(GenericArrayTypeConverter<short>)); |
||||
|
this.AddTypeConverter(typeof(ushort[]), typeof(GenericArrayTypeConverter<ushort>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(int[]), typeof(GenericArrayTypeConverter<int>)); |
||||
|
this.AddTypeConverter(typeof(uint[]), typeof(GenericArrayTypeConverter<uint>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(long[]), typeof(GenericArrayTypeConverter<long>)); |
||||
|
this.AddTypeConverter(typeof(ulong[]), typeof(GenericArrayTypeConverter<ulong>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(decimal[]), typeof(GenericArrayTypeConverter<decimal>)); |
||||
|
this.AddTypeConverter(typeof(float[]), typeof(GenericArrayTypeConverter<float>)); |
||||
|
this.AddTypeConverter(typeof(double[]), typeof(GenericArrayTypeConverter<double>)); |
||||
|
|
||||
|
this.AddTypeConverter(typeof(string[]), typeof(GenericArrayTypeConverter<string>)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the default value for the given type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">
|
||||
|
/// The <see cref="Type"/> to return.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="object"/> representing the default value.
|
||||
|
/// </returns>
|
||||
|
/// <exception cref="ArgumentNullException">
|
||||
|
/// Thrown if the given <see cref="Type"/> is null.
|
||||
|
/// </exception>
|
||||
|
private object GetDefaultValue(Type type) |
||||
|
{ |
||||
|
// Validate parameters.
|
||||
|
if (type == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException("type"); |
||||
|
} |
||||
|
|
||||
|
// We want an Func<object> which returns the default.
|
||||
|
// Create that expression here.
|
||||
|
// Have to convert to object.
|
||||
|
// The default value, always get what the *code* tells us.
|
||||
|
Expression<Func<object>> e = |
||||
|
Expression.Lambda<Func<object>>( |
||||
|
Expression.Convert(Expression.Default(type), typeof(object))); |
||||
|
|
||||
|
// Compile and return the value.
|
||||
|
return e.Compile()(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,2 +1,3 @@ |
|||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> |
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=configuration_005Cshared/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> |
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=configuration_005Cshared/@EntryIndexedValue">True</s:Boolean> |
||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers_005Cquerystringparser/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> |
||||
@ -0,0 +1,136 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="IOHelper.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// Provides helper method for traversing the file system.
|
||||
|
// <remarks>
|
||||
|
// Adapted from identically named class within <see href="https://github.com/umbraco/Umbraco-CMS" />
|
||||
|
// </remarks>
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Common.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.IO; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
using ImageProcessor.Common.Extensions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides helper method for traversing the file system.
|
||||
|
/// <remarks>
|
||||
|
/// Adapted from identically named class within <see href="https://github.com/umbraco/Umbraco-CMS"/>
|
||||
|
/// </remarks>
|
||||
|
/// </summary>
|
||||
|
internal class IOHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The root directory.
|
||||
|
/// </summary>
|
||||
|
private static string rootDirectory; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Maps a virtual path to a physical path.
|
||||
|
/// </summary>
|
||||
|
/// <param name="virtualPath">
|
||||
|
/// The virtual path to map.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="string"/> representing the physical path.
|
||||
|
/// </returns>
|
||||
|
public static string MapPath(string virtualPath) |
||||
|
{ |
||||
|
// Check if the path is already mapped
|
||||
|
// UNC Paths start with "\\". If the site is running off a network drive mapped paths
|
||||
|
// will look like "\\Whatever\Boo\Bar"
|
||||
|
if ((virtualPath.Length >= 2 && virtualPath[1] == Path.VolumeSeparatorChar) |
||||
|
|| virtualPath.StartsWith(@"\\")) |
||||
|
{ |
||||
|
return virtualPath; |
||||
|
} |
||||
|
|
||||
|
char separator = Path.DirectorySeparatorChar; |
||||
|
string root = GetRootDirectorySafe(); |
||||
|
string newPath = virtualPath.TrimStart('~', '/').Replace('/', separator); |
||||
|
return root + separator.ToString(CultureInfo.InvariantCulture) + newPath; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the root directory bin folder for the currently running application.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="string"/> representing the root directory bin folder.
|
||||
|
/// </returns>
|
||||
|
public static string GetRootDirectoryBinFolder() |
||||
|
{ |
||||
|
string binFolder = string.Empty; |
||||
|
if (string.IsNullOrEmpty(rootDirectory)) |
||||
|
{ |
||||
|
DirectoryInfo directoryInfo = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory; |
||||
|
if (directoryInfo != null) |
||||
|
{ |
||||
|
binFolder = directoryInfo.FullName; |
||||
|
} |
||||
|
|
||||
|
return binFolder; |
||||
|
} |
||||
|
|
||||
|
binFolder = Path.Combine(GetRootDirectorySafe(), "bin"); |
||||
|
|
||||
|
#if DEBUG
|
||||
|
string debugFolder = Path.Combine(binFolder, "debug"); |
||||
|
if (Directory.Exists(debugFolder)) |
||||
|
{ |
||||
|
return debugFolder; |
||||
|
} |
||||
|
#endif
|
||||
|
string releaseFolder = Path.Combine(binFolder, "release"); |
||||
|
if (Directory.Exists(releaseFolder)) |
||||
|
{ |
||||
|
return releaseFolder; |
||||
|
} |
||||
|
|
||||
|
if (Directory.Exists(binFolder)) |
||||
|
{ |
||||
|
return binFolder; |
||||
|
} |
||||
|
|
||||
|
return rootDirectory; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the path to the root of the application, by getting the path to where the assembly where this
|
||||
|
/// method is included is present, then traversing until it's past the /bin directory. I.e. this makes it work
|
||||
|
/// even if the assembly is in a /bin/debug or /bin/release folder
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="string"/> representing the root path of the currently running application.</returns>
|
||||
|
internal static string GetRootDirectorySafe() |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(rootDirectory) == false) |
||||
|
{ |
||||
|
return rootDirectory; |
||||
|
} |
||||
|
|
||||
|
string codeBase = Assembly.GetExecutingAssembly().CodeBase; |
||||
|
Uri uri = new Uri(codeBase); |
||||
|
string path = uri.LocalPath; |
||||
|
string baseDirectory = Path.GetDirectoryName(path); |
||||
|
if (string.IsNullOrEmpty(baseDirectory)) |
||||
|
{ |
||||
|
throw new Exception( |
||||
|
"No root directory could be resolved. Please ensure that your solution is correctly configured."); |
||||
|
} |
||||
|
|
||||
|
rootDirectory = baseDirectory.Contains("bin") |
||||
|
? baseDirectory.Substring(0, baseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase) - 1) |
||||
|
: baseDirectory; |
||||
|
|
||||
|
return rootDirectory; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,288 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="TypeFinder.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
|
// of the web application.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Common.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Diagnostics; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Security; |
||||
|
using System.Threading; |
||||
|
|
||||
|
using ImageProcessor.Common.Extensions; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
|
/// of the web application.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Adapted from identically named class within <see href="https://github.com/umbraco/Umbraco-CMS"/>
|
||||
|
/// </remarks>
|
||||
|
internal static class TypeFinder |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The local filtered assembly cache.
|
||||
|
/// </summary>
|
||||
|
private static readonly HashSet<Assembly> LocalFilteredAssemblyCache = new HashSet<Assembly>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The local filtered assembly cache locker.
|
||||
|
/// </summary>
|
||||
|
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The reader-writer lock implementation.
|
||||
|
/// </summary>
|
||||
|
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// An assembly filter collection to filter out known types that definitely don't contain types
|
||||
|
/// we'd like to find or plugins.
|
||||
|
/// Umbraco uses ImageProcessor in it's core so add common exclusion files from that.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// NOTE the comma versus period... comma delimits the name in an Assembly FullName property so
|
||||
|
/// if it ends with comma then its an exact name match.
|
||||
|
/// </remarks>
|
||||
|
private static readonly string[] KnownAssemblyExclusionFilter = |
||||
|
{ |
||||
|
"mscorlib,", "System.", "Antlr3.", "Autofac.", |
||||
|
"Autofac,", "Castle.", "ClientDependency.", |
||||
|
"DataAnnotationsExtensions.", |
||||
|
"DataAnnotationsExtensions,", "Dynamic,", |
||||
|
"HtmlDiff,", "Iesi.Collections,", "log4net,", |
||||
|
"Microsoft.", "Newtonsoft.", "NHibernate.", |
||||
|
"NHibernate,", "NuGet.", "RouteDebugger,", |
||||
|
"SqlCE4Umbraco,", "umbraco.datalayer,", |
||||
|
"umbraco.interfaces,", |
||||
|
"umbraco.webservices", "Lucene.", "Examine,", |
||||
|
"Examine.", "ServiceStack.", "MySql.", |
||||
|
"HtmlAgilityPack.", "TidyNet.", |
||||
|
"ICSharpCode.", "CookComputing.", |
||||
|
"AutoMapper,", "AutoMapper.", |
||||
|
"AzureDirectory,", "itextsharp,", |
||||
|
"UrlRewritingNet.", "HtmlAgilityPack,", |
||||
|
"MiniProfiler,", "Moq,", "nunit.framework,", |
||||
|
"TidyNet,", "WebDriver," |
||||
|
}; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A collection of all assemblies.
|
||||
|
/// </summary>
|
||||
|
private static HashSet<Assembly> allAssemblies; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The bin folder assemblies.
|
||||
|
/// </summary>
|
||||
|
private static HashSet<Assembly> binFolderAssemblies; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Lazily loads a reference to all assemblies and only local assemblies.
|
||||
|
/// This is a modified version of:
|
||||
|
/// <see href="http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder"/>
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
|
/// loaded in the CLR, not all assemblies.
|
||||
|
/// See these threads:
|
||||
|
/// <see href="http://issues.umbraco.org/issue/U5-198"/>
|
||||
|
/// <see cref="http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app"/>
|
||||
|
/// <see cref="http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl"/>
|
||||
|
/// </remarks>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="HashSet{Assembly}"/>.
|
||||
|
/// </returns>
|
||||
|
internal static HashSet<Assembly> GetAllAssemblies() |
||||
|
{ |
||||
|
using (UpgradeableReadLock locker = new UpgradeableReadLock(Locker)) |
||||
|
{ |
||||
|
if (allAssemblies == null) |
||||
|
{ |
||||
|
locker.UpgradeToWriteLock(); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
// NOTE: we cannot use AppDomain.CurrentDomain.GetAssemblies() because this only returns assemblies that have
|
||||
|
// already been loaded in to the app domain, instead we will look directly into the bin folder and load each one.
|
||||
|
string binFolder = IOHelper.GetRootDirectoryBinFolder(); |
||||
|
List<string> binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList(); |
||||
|
HashSet<Assembly> assemblies = new HashSet<Assembly>(); |
||||
|
|
||||
|
foreach (string file in binAssemblyFiles) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
AssemblyName assemblyName = AssemblyName.GetAssemblyName(file); |
||||
|
assemblies.Add(Assembly.Load(assemblyName)); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
if (ex is SecurityException || ex is BadImageFormatException) |
||||
|
{ |
||||
|
// Swallow exception but allow debugging.
|
||||
|
Debug.WriteLine(ex.Message); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
|
if (!assemblies.Any()) |
||||
|
{ |
||||
|
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) |
||||
|
{ |
||||
|
assemblies.Add(assembly); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Here we are trying to get the App_Code assembly
|
||||
|
string[] fileExtensions = { ".cs", ".vb" }; |
||||
|
DirectoryInfo appCodeFolder = new DirectoryInfo(IOHelper.MapPath("~/App_code")); |
||||
|
|
||||
|
// Check if the folder exists and if there are any files in it with the supported file extensions
|
||||
|
if (appCodeFolder.Exists && fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())) |
||||
|
{ |
||||
|
Assembly appCodeAssembly = Assembly.Load("App_Code"); |
||||
|
if (!assemblies.Contains(appCodeAssembly)) |
||||
|
{ |
||||
|
assemblies.Add(appCodeAssembly); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Now set the allAssemblies
|
||||
|
allAssemblies = new HashSet<Assembly>(assemblies); |
||||
|
} |
||||
|
catch (InvalidOperationException e) |
||||
|
{ |
||||
|
if (!(e.InnerException is SecurityException)) |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
|
||||
|
binFolderAssemblies = allAssemblies; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return allAssemblies; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// The collection of assemblies.
|
||||
|
/// </returns>
|
||||
|
internal static HashSet<Assembly> GetBinAssemblies() |
||||
|
{ |
||||
|
if (binFolderAssemblies == null) |
||||
|
{ |
||||
|
using (new WriteLock(Locker)) |
||||
|
{ |
||||
|
Assembly[] assemblies = GetAssembliesWithKnownExclusions().ToArray(); |
||||
|
DirectoryInfo binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory; |
||||
|
// ReSharper disable once PossibleNullReferenceException
|
||||
|
List<string> binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList(); |
||||
|
IEnumerable<AssemblyName> domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName); |
||||
|
HashSet<Assembly> safeDomainAssemblies = new HashSet<Assembly>(); |
||||
|
HashSet<Assembly> binFolderAssemblyList = new HashSet<Assembly>(); |
||||
|
|
||||
|
foreach (Assembly assembly in assemblies) |
||||
|
{ |
||||
|
safeDomainAssemblies.Add(assembly); |
||||
|
} |
||||
|
|
||||
|
foreach (AssemblyName assemblyName in domainAssemblyNames) |
||||
|
{ |
||||
|
Assembly foundAssembly = safeDomainAssemblies |
||||
|
.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile()); |
||||
|
|
||||
|
if (foundAssembly != null) |
||||
|
{ |
||||
|
binFolderAssemblyList.Add(foundAssembly); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
binFolderAssemblies = new HashSet<Assembly>(binFolderAssemblyList); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return binFolderAssemblies; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
|
/// and excluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
|
/// cached for performance reasons.
|
||||
|
/// </summary>
|
||||
|
/// <param name="excludeFromResults">
|
||||
|
/// An <see cref="IEnumerable{Assembly}"/> to exclude.
|
||||
|
/// </param>
|
||||
|
/// <returns>The collection of local assemblies.</returns>
|
||||
|
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions( |
||||
|
IEnumerable<Assembly> excludeFromResults = null) |
||||
|
{ |
||||
|
using (UpgradeableReadLock locker = new UpgradeableReadLock(LocalFilteredAssemblyCacheLocker)) |
||||
|
{ |
||||
|
if (LocalFilteredAssemblyCache.Any()) |
||||
|
{ |
||||
|
return LocalFilteredAssemblyCache; |
||||
|
} |
||||
|
|
||||
|
locker.UpgradeToWriteLock(); |
||||
|
|
||||
|
IEnumerable<Assembly> assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter); |
||||
|
foreach (Assembly assembly in assemblies) |
||||
|
{ |
||||
|
LocalFilteredAssemblyCache.Add(assembly); |
||||
|
} |
||||
|
|
||||
|
return LocalFilteredAssemblyCache; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Return a distinct list of found local Assemblies and excluding the ones passed in and excluding the exclusion list filter
|
||||
|
/// </summary>
|
||||
|
/// <param name="excludeFromResults">
|
||||
|
/// An <see cref="IEnumerable{Assembly}"/> to exclude.
|
||||
|
/// </param>
|
||||
|
/// <param name="exclusionFilter">
|
||||
|
/// An <see cref="string"/> array containing exclusion filters.
|
||||
|
/// </param>
|
||||
|
/// <returns>The collection of filtered local assemblies.</returns>
|
||||
|
private static IEnumerable<Assembly> GetFilteredAssemblies( |
||||
|
IEnumerable<Assembly> excludeFromResults = null, |
||||
|
string[] exclusionFilter = null) |
||||
|
{ |
||||
|
if (excludeFromResults == null) |
||||
|
{ |
||||
|
excludeFromResults = new HashSet<Assembly>(); |
||||
|
} |
||||
|
|
||||
|
if (exclusionFilter == null) |
||||
|
{ |
||||
|
exclusionFilter = new string[] { }; |
||||
|
} |
||||
|
|
||||
|
return GetAllAssemblies() |
||||
|
.Where(x => !excludeFromResults.Contains(x) |
||||
|
&& !x.GlobalAssemblyCache |
||||
|
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,126 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="UpgradeableReadLock.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// Provides a convenience methodology for implementing upgradeable locked access to resources.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Common.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides a convenience methodology for implementing upgradeable locked access to resources.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Adapted from identically named class within <see href="https://github.com/umbraco/Umbraco-CMS"/>
|
||||
|
/// </remarks>
|
||||
|
internal sealed class UpgradeableReadLock : IDisposable |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The locker to lock against.
|
||||
|
/// </summary>
|
||||
|
private readonly ReaderWriterLockSlim locker; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A value indicating whether the locker has been upgraded to a writeable lock.
|
||||
|
/// </summary>
|
||||
|
private bool upgraded; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A value indicating whether this instance of the given entity has been disposed.
|
||||
|
/// </summary>
|
||||
|
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
|
||||
|
/// <remarks>
|
||||
|
/// If the entity is disposed, it must not be disposed a second
|
||||
|
/// time. The isDisposed field is set the first time the entity
|
||||
|
/// is disposed. If the isDisposed field is true, then the Dispose()
|
||||
|
/// method will not dispose again. This help not to prolong the entity's
|
||||
|
/// life in the Garbage Collector.
|
||||
|
/// </remarks>
|
||||
|
private bool isDisposed; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="UpgradeableReadLock"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="locker">
|
||||
|
/// The locker.
|
||||
|
/// </param>
|
||||
|
public UpgradeableReadLock(ReaderWriterLockSlim locker) |
||||
|
{ |
||||
|
this.locker = locker; |
||||
|
this.locker.EnterUpgradeableReadLock(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Finalizes an instance of the <see cref="UpgradeableReadLock"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Use C# destructor syntax for finalization code.
|
||||
|
/// This destructor will run only if the Dispose method
|
||||
|
/// does not get called.
|
||||
|
/// It gives your base class the opportunity to finalize.
|
||||
|
/// Do not provide destructors in types derived from this class.
|
||||
|
/// </remarks>
|
||||
|
~UpgradeableReadLock() |
||||
|
{ |
||||
|
// Do not re-create Dispose clean-up code here.
|
||||
|
// Calling Dispose(false) is optimal in terms of
|
||||
|
// readability and maintainability.
|
||||
|
this.Dispose(false); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Tries to enter the locker in write mode.
|
||||
|
/// </summary>
|
||||
|
public void UpgradeToWriteLock() |
||||
|
{ |
||||
|
this.locker.EnterWriteLock(); |
||||
|
this.upgraded = true; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Disposes the object and frees resources for the Garbage Collector.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
this.Dispose(true); |
||||
|
|
||||
|
// This object will be cleaned up by the Dispose method.
|
||||
|
// Therefore, you should call GC.SuppressFinalize to
|
||||
|
// take this object off the finalization queue
|
||||
|
// and prevent finalization code for this object
|
||||
|
// from executing a second time.
|
||||
|
GC.SuppressFinalize(this); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Disposes the object and frees resources for the Garbage Collector.
|
||||
|
/// </summary>
|
||||
|
/// <param name="disposing">If true, the object gets disposed.</param>
|
||||
|
private void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (this.isDisposed) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (disposing) |
||||
|
{ |
||||
|
if (this.upgraded) |
||||
|
{ |
||||
|
this.locker.ExitWriteLock(); |
||||
|
} |
||||
|
|
||||
|
this.locker.ExitUpgradeableReadLock(); |
||||
|
} |
||||
|
|
||||
|
// Note disposing is done.
|
||||
|
this.isDisposed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,107 @@ |
|||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
// <copyright file="WriteLock.cs" company="James South">
|
||||
|
// Copyright (c) James South.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
// </copyright>
|
||||
|
// <summary>
|
||||
|
// Provides a convenience methodology for implementing writeable locked access to resources.
|
||||
|
// </summary>
|
||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
|
||||
|
namespace ImageProcessor.Common.Helpers |
||||
|
{ |
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Provides a convenience methodology for implementing writable locked access to resources.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Adapted from identically named class within <see href="https://github.com/umbraco/Umbraco-CMS"/>
|
||||
|
/// </remarks>
|
||||
|
internal sealed class WriteLock : IDisposable |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The locker to lock against.
|
||||
|
/// </summary>
|
||||
|
private readonly ReaderWriterLockSlim locker; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A value indicating whether this instance of the given entity has been disposed.
|
||||
|
/// </summary>
|
||||
|
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
|
||||
|
/// <remarks>
|
||||
|
/// If the entity is disposed, it must not be disposed a second
|
||||
|
/// time. The isDisposed field is set the first time the entity
|
||||
|
/// is disposed. If the isDisposed field is true, then the Dispose()
|
||||
|
/// method will not dispose again. This help not to prolong the entity's
|
||||
|
/// life in the Garbage Collector.
|
||||
|
/// </remarks>
|
||||
|
private bool isDisposed; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="WriteLock"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="locker">
|
||||
|
/// The locker.
|
||||
|
/// </param>
|
||||
|
public WriteLock(ReaderWriterLockSlim locker) |
||||
|
{ |
||||
|
this.locker = locker; |
||||
|
this.locker.EnterWriteLock(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Finalizes an instance of the <see cref="WriteLock"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Use C# destructor syntax for finalization code.
|
||||
|
/// This destructor will run only if the Dispose method
|
||||
|
/// does not get called.
|
||||
|
/// It gives your base class the opportunity to finalize.
|
||||
|
/// Do not provide destructors in types derived from this class.
|
||||
|
/// </remarks>
|
||||
|
~WriteLock() |
||||
|
{ |
||||
|
// Do not re-create Dispose clean-up code here.
|
||||
|
// Calling Dispose(false) is optimal in terms of
|
||||
|
// readability and maintainability.
|
||||
|
this.Dispose(false); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Disposes the object and frees resources for the Garbage Collector.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
this.Dispose(true); |
||||
|
|
||||
|
// This object will be cleaned up by the Dispose method.
|
||||
|
// Therefore, you should call GC.SuppressFinalize to
|
||||
|
// take this object off the finalization queue
|
||||
|
// and prevent finalization code for this object
|
||||
|
// from executing a second time.
|
||||
|
GC.SuppressFinalize(this); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Disposes the object and frees resources for the Garbage Collector.
|
||||
|
/// </summary>
|
||||
|
/// <param name="disposing">If true, the object gets disposed.</param>
|
||||
|
private void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (this.isDisposed) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (disposing) |
||||
|
{ |
||||
|
this.locker.ExitWriteLock(); |
||||
|
} |
||||
|
|
||||
|
// Note disposing is done.
|
||||
|
this.isDisposed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue