merged in patch for TypeFinder changes

This commit is contained in:
Shannon Deminick
2013-04-29 19:55:44 -10:00
parent ad06aded1b
commit 6d994f48ac
3 changed files with 629 additions and 37 deletions

View File

@@ -143,7 +143,8 @@ namespace Umbraco.Core
{
try
{
var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
var foundAssembly =
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
if (foundAssembly != null)
{
binFolderAssemblies.Add(foundAssembly);
@@ -255,11 +256,17 @@ namespace Umbraco.Core
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
}
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies,
bool onlyConcreteClasses)
where TAttribute : Attribute
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
// a assembly cant contain types that are assignable to a type it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (T), assemblies);
// a assembly cant contain types with a attribute it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(typeof (TAttribute), assemblies);
var l = new List<Type>();
foreach(var a in assemblies)
{
@@ -330,23 +337,57 @@ namespace Umbraco.Core
/// <param name="assemblies">The assemblies.</param>
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesWithAttribute(Type type, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
public static IEnumerable<Type> FindClassesWithAttribute(Type type, IEnumerable<Assembly> assemblies,
bool onlyConcreteClasses)
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
if (!TypeHelper.IsTypeAssignableFrom<Attribute>(type))
throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
// a assembly cant contain types with a attribute it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(type, assemblies);
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface && t.GetCustomAttributes(type, false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
where
!t.IsInterface && t.GetCustomAttributes(type, false).Any() &&
(!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
}
/// <summary>
/// Removes assemblies that doesn't reference the assembly of the type we are looking for.
/// </summary>
/// <param name="type"></param>
/// <param name="assemblies"></param>
/// <returns></returns>
private static IEnumerable<Assembly> RemoveAssembliesThatDontReferenceAssemblyOfType(Type type, IEnumerable<Assembly> assemblies)
{
// Avoid scanning assembly if it doesn't contain a reference to the assembly containing the type we are looking for
// to the assembly containing the attribute we are looking for
var assemblyNameOfType = type.Assembly.GetName().Name;
return assemblies
.Where(assembly => assembly == type.Assembly
|| HasReferenceToAssemblyWithName(assembly, assemblyNameOfType)).ToList();
}
/// <summary>
/// checks if the assembly has a reference with the same name as the expected assembly name.
/// </summary>
/// <param name="assembly"></param>
/// <param name="expectedAssemblyName"></param>
/// <returns></returns>
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
{
return assembly
.GetReferencedAssemblies()
.Select(a => a.Name)
.Contains(expectedAssemblyName, StringComparer.Ordinal);
}
/// <summary>
/// Finds the classes with attribute.
@@ -388,12 +429,17 @@ namespace Umbraco.Core
private static IEnumerable<Type> GetTypes(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
// a assembly cant contain types that are assignable to a type it doesn't reference
assemblies = RemoveAssembliesThatDontReferenceAssemblyOfType(assignTypeFrom, assemblies);
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
var types = from t in GetTypesWithFormattedException(a)
where
!t.IsInterface && assignTypeFrom.IsAssignableFrom(t) &&
(!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
@@ -411,7 +457,7 @@ namespace Umbraco.Core
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
{
sb.AppendLine("Exception: " + loaderException.ToString());
sb.AppendLine("Exception: " + loaderException);
}
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
}

View File

@@ -1,19 +1,31 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Compilation;
using NUnit.Framework;
using SqlCE4Umbraco;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Tests;
using Umbraco.Tests.PartialTrust;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.BaseRest;
using umbraco;
using umbraco.DataLayer;
using umbraco.MacroEngines;
using umbraco.businesslogic;
using umbraco.cms.businesslogic;
using umbraco.editorControls.tags;
using umbraco.interfaces;
using umbraco.uicontrols;
namespace Umbraco.Tests
@@ -50,45 +62,561 @@ namespace Umbraco.Tests
typeof(System.Web.Mvc.ActionResult).Assembly,
typeof(TypeFinder).Assembly,
typeof(ISqlHelper).Assembly,
typeof(ICultureDictionary).Assembly
typeof(ICultureDictionary).Assembly,
typeof(Tag).Assembly
};
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MyTestAttribute : Attribute
{
}
public abstract class TestEditor
{
}
[MyTestAttribute]
public class BenchmarkTestEditor : TestEditor
{
}
[MyTestAttribute]
public class MyOtherTestEditor : TestEditor
{
}
[Test]
public void Get_Type_With_Attribute()
public void Find_Class_Of_Type_With_Attribute()
{
var typesFound = TypeFinder.FindClassesOfTypeWithAttribute<TestEditor, MyTestAttribute>(_assemblies);
Assert.AreEqual(2, typesFound.Count());
}
[Test]
public void Find_Classes_Of_Type()
{
var typesFound = TypeFinder.FindClassesOfType<ITag>(_assemblies);
Assert.AreEqual(2, typesFound.Count());
}
[Test]
public void Find_Classes_With_Attribute()
{
var typesFound = TypeFinder.FindClassesWithAttribute<RestExtensionAttribute>(_assemblies);
Assert.AreEqual(1, typesFound.Count());
}
[Ignore]
[Test]
public void Benchmark_Original_Finder()
{
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting test", "Finished test"))
{
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesOfType", "Finished FindClassesOfType"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinderOriginal.FindClassesOfType<DisposableObject>(_assemblies).Count(), 0);
}
}
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinderOriginal.FindClassesOfTypeWithAttribute<TestEditor, MyTestAttribute>(_assemblies).Count(), 0);
}
}
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinderOriginal.FindClassesWithAttribute<XsltExtensionAttribute>(_assemblies).Count(), 0);
}
}
}
}
[Ignore]
[Test]
public void Benchmark_New_Finder()
{
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting test", "Finished test"))
{
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesOfType", "Finished FindClassesOfType"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinder.FindClassesOfType<DisposableObject>(_assemblies).Count(), 0);
}
}
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesOfTypeWithAttribute", "Finished FindClassesOfTypeWithAttribute"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinder.FindClassesOfTypeWithAttribute<TestEditor, MyTestAttribute>(_assemblies).Count(), 0);
}
}
using (DisposableTimer.TraceDuration<TypeFinderTests>("Starting FindClassesWithAttribute", "Finished FindClassesWithAttribute"))
{
for (var i = 0; i < 1000; i++)
{
Assert.Greater(TypeFinder.FindClassesWithAttribute<XsltExtensionAttribute>(_assemblies).Count(), 0);
}
}
}
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MyTestAttribute : Attribute
{
}
public abstract class TestEditor
{
}
[MyTestAttribute]
public class BenchmarkTestEditor : TestEditor
{
}
[MyTestAttribute]
public class MyOtherTestEditor : TestEditor
{
}
//USED FOR THE ABOVE TESTS
// see this issue for details: http://issues.umbraco.org/issue/U4-1187
internal static class TypeFinderOriginal
{
private static readonly ConcurrentBag<Assembly> LocalFilteredAssemblyCache = new ConcurrentBag<Assembly>();
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
private static ReadOnlyCollection<Assembly> _allAssemblies = null;
private static ReadOnlyCollection<Assembly> _binFolderAssemblies = null;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
/// <summary>
/// lazily load a reference to all assemblies and only local assemblies.
/// This is a modified version of: 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:
/// http://issues.umbraco.org/issue/U5-198
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
/// </remarks>
internal static IEnumerable<Assembly> GetAllAssemblies()
{
if (_allAssemblies == null)
{
using (new WriteLock(Locker))
{
List<Assembly> assemblies = null;
try
{
var isHosted = HttpContext.Current != null;
try
{
if (isHosted)
{
assemblies = new List<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
}
}
catch (InvalidOperationException e)
{
if (!(e.InnerException is SecurityException))
throw;
}
if (assemblies == null)
{
//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.
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
assemblies = new List<Assembly>();
foreach (var a in binAssemblyFiles)
{
try
{
var assName = AssemblyName.GetAssemblyName(a);
var ass = Assembly.Load(assName);
assemblies.Add(ass);
}
catch (Exception e)
{
if (e is SecurityException || e is BadImageFormatException)
{
//swallow these exceptions
}
else
{
throw;
}
}
}
}
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
if (!assemblies.Any())
{
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
}
//here we are trying to get the App_Code assembly
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/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())))
{
var appCodeAssembly = Assembly.Load("App_Code");
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
assemblies.Add(appCodeAssembly);
}
//now set the _allAssemblies
_allAssemblies = new ReadOnlyCollection<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></returns>
/// <remarks>
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
/// </remarks>
internal static IEnumerable<Assembly> GetBinAssemblies()
{
if (_binFolderAssemblies == null)
{
using (new WriteLock(Locker))
{
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
var safeDomainAssemblies = new List<Assembly>();
var binFolderAssemblies = new List<Assembly>();
foreach (var a in assemblies)
{
try
{
//do a test to see if its queryable in med trust
var assemblyFile = a.GetAssemblyFile();
safeDomainAssemblies.Add(a);
}
catch (SecurityException)
{
//we will just ignore this because this will fail
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
//an assembly that is ok.
}
}
foreach (var assemblyName in domainAssemblyNames)
{
try
{
var foundAssembly = safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
if (foundAssembly != null)
{
binFolderAssemblies.Add(foundAssembly);
}
}
catch (SecurityException)
{
//we will just ignore this because if we are trying to do a call to:
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
//an assembly that is ok.
}
}
_binFolderAssemblies = new ReadOnlyCollection<Assembly>(binFolderAssemblies);
}
}
return _binFolderAssemblies;
}
/// <summary>
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
/// cached for perforance reasons.
/// </summary>
/// <param name="excludeFromResults"></param>
/// <returns></returns>
internal static IEnumerable<Assembly> GetAssembliesWithKnownExclusions(
IEnumerable<Assembly> excludeFromResults = null)
{
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
using (new WriteLock(LocalFilteredAssemblyCacheLocker))
{
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
assemblies.ForEach(LocalFilteredAssemblyCache.Add);
}
return LocalFilteredAssemblyCache;
}
/// <summary>
/// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
/// </summary>
/// <param name="excludeFromResults"></param>
/// <param name="exclusionFilter"></param>
/// <returns></returns>
private static IEnumerable<Assembly> GetFilteredAssemblies(
IEnumerable<Assembly> excludeFromResults = null,
string[] exclusionFilter = null)
{
if (excludeFromResults == null)
excludeFromResults = new List<Assembly>();
if (exclusionFilter == null)
exclusionFilter = new string[] { };
return GetAllAssemblies()
.Where(x => !excludeFromResults.Contains(x)
&& !x.GlobalAssemblyCache
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
}
/// <summary>
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
/// </summary>
/// <remarks>
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
/// </remarks>
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
{
"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.providers,",
"Umbraco.Web.UI,",
"umbraco.webservices",
"Lucene.",
"Examine,",
"Examine.",
"ServiceStack.",
"MySql.",
"HtmlAgilityPack.",
"TidyNet.",
"ICSharpCode.",
"CookComputing."
};
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
where TAttribute : Attribute
{
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
}
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
where TAttribute : Attribute
{
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
}
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
where TAttribute : Attribute
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface
&& typeof(T).IsAssignableFrom(t)
&& t.GetCustomAttributes<TAttribute>(false).Any()
&& (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
}
/// <summary>
/// Searches all filtered local assemblies specified for classes of the type passed in.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> FindClassesOfType<T>()
{
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
}
/// <summary>
/// Returns all types found of in the assemblies specified of type T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies"></param>
/// <param name="onlyConcreteClasses"></param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
return GetAssignablesFromType<T>(assemblies, onlyConcreteClasses);
}
/// <summary>
/// Returns all types found of in the assemblies specified of type T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies"></param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
{
return FindClassesOfType<T>(assemblies, true);
}
/// <summary>
/// Finds the classes with attribute.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies">The assemblies.</param>
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
where T : Attribute
{
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
}
/// <summary>
/// Finds the classes with attribute.
/// </summary>
/// <param name="type">The attribute type </param>
/// <param name="assemblies">The assemblies.</param>
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesWithAttribute(Type type, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
if (assemblies == null) throw new ArgumentNullException("assemblies");
if (!TypeHelper.IsTypeAssignableFrom<Attribute>(type))
throw new ArgumentException("The type specified: " + type + " is not an Attribute type");
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface && t.GetCustomAttributes(type, false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
}
/// <summary>
/// Finds the classes with attribute.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies">The assemblies.</param>
/// <returns></returns>
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
where T : Attribute
{
return FindClassesWithAttribute<T>(assemblies, true);
}
/// <summary>
/// Finds the classes with attribute in filtered local assemblies
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> FindClassesWithAttribute<T>()
where T : Attribute
{
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
}
#region Private methods
/// <summary>
/// Gets a collection of assignables of type T from a collection of assemblies
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies"></param>
/// <param name="onlyConcreteClasses"></param>
/// <returns></returns>
private static IEnumerable<Type> GetAssignablesFromType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
return GetTypes(typeof(T), assemblies, onlyConcreteClasses);
}
private static IEnumerable<Type> GetTypes(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
{
var l = new List<Type>();
foreach (var a in assemblies)
{
var types = from t in GetTypesWithFormattedException(a)
where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract))
select t;
l.AddRange(types);
}
return l;
}
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
{
//if the assembly is dynamic, do not try to scan it
if (a.IsDynamic)
return Enumerable.Empty<Type>();
try
{
return a.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
{
var sb = new StringBuilder();
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
{
sb.AppendLine("Exception: " + loaderException.ToString());
}
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
}
}
#endregion
}
}
}

View File

@@ -22,6 +22,24 @@ namespace Umbraco.Web
public static class HtmlHelperRenderExtensions
{
/// <summary>
/// Renders a partial view that is found in the specified area
/// </summary>
/// <param name="helper"></param>
/// <param name="partial"></param>
/// <param name="area"></param>
/// <param name="model"></param>
/// <param name="viewData"></param>
/// <returns></returns>
public static MvcHtmlString AreaPartial(this HtmlHelper helper, string partial, string area, object model = null, ViewDataDictionary viewData = null)
{
var originalArea = helper.ViewContext.RouteData.DataTokens["area"];
helper.ViewContext.RouteData.DataTokens["area"] = area;
var result = helper.Partial(partial, model, viewData);
helper.ViewContext.RouteData.DataTokens["area"] = originalArea;
return result;
}
/// <summary>
/// Will render the preview badge when in preview mode which is not required ever unless the MVC page you are
/// using does not inherit from UmbracoTemplatePage
/// </summary>