Asi je známou věcí, že .NET Framework ve verzi pro Silverlight neobsahuje úplně všechny metody a neumožňuje úplně všechny možnosti jako standardní “velký” framework. Důvody jsou v celku jasné např. izolace Silvelight aplikace v tzv. sandboxu, nároky na bezpečnost a snaha o to, aby byl Silverlight plugin co nejmenší. Jedno z chybějících API je i získání seznamu aktuálně načtených assembly:
internal static class TypeHelper
{
#region action methods
public static Type GetType(string typeName)
{
foreach (var assembly in GetLoadedAssemblies())
{
var type = assembly.GetType(typeName, false);
if (type != null)
{
return type;
}
}
return null;
}
#endregion
#region private member functions
private static IEnumerable<System.Reflection.Assembly> GetLoadedAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies(); //<—-not supported in Silverlight!
}
#endregion
}
To je užitečné pokud potřebujeme vrátit objekt typu Type pro string, který obsahuje název datového typu (type name qualified by its namespace – např. “System.Windows.Application”), ale nikoliv jméno typu včetně názvu assembly (assembly-qualified name – např. “System.Windows.Application, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e”) tj. jinými slovy neznáme z jaké assembly daný typ pochází (*).
Výše uvedený kód to právě řeší tak, že prochází všechny aktuálně načtené assembly a typ hledá postupně v nich. To, že příslušná assembly bude v dané chvíli načtena, se v běžném případě dá považovat za rozumný předpoklad.
Jak tedy vrátit seznam načtených assembly v Silverlightu tj. nahradit nepodporované volání:
AppDomain.CurrentDomain.GetAssemblies();
Základem řešení je manifest .xap balíčku Silverlight aplikace, který umožňuje jako tzv. parts vrátit assembly, které jsou v něm obsažené:
var assemblies = from part in System.Windows.Deployment.Current.Parts
let resourceStream = System.Windows.Application.GetResourceStream(new Uri(part.Source, UriKind.Relative))
select new System.Windows.AssemblyPart().Load(resourceStream.Stream);
Je tu ale ještě jeden problém a tím je to, že toto vrací pouze assembly jiné než z Silverlight runtime, které se v .xap balíčku nenachází. Konkrétně se jedná o tyto assembly:
- mscorlib.dll
- system.dll
- System.Core.dll
- System.Net.dll
- System.Runtime.Serialization.dll
- System.ServiceModel.dll
- System.ServiceModel.Web.dll
- System.Windows.dll
- System.Windows.Browser.dll
- System.Xml.dll
Z adresáře:
C:\Program Files (x86)\Microsoft Silverlight\<verze Silverlight>
resp. z adresáře:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0
V podstatě nezbývá nic jiného než tyto assembly resp. ty důležité z nich (např. pouze ty referencované v našem projektu) k seznamu “navrdo” přidat. Finální řešení bude potom vypadat takto:
internal static class TypeHelper
{
#region action methods
public static Type GetType(string typeName)
{
foreach (var assembly in GetLoadedAssemblies())
{
var type = assembly.GetType(typeName, false);
if (type != null)
{
return type;
}
}
return null;
}
#endregion
#region private member functions
private static IEnumerable<System.Reflection.Assembly> GetLoadedAssemblies()
{
#if !SILVERLIGHT
return AppDomain.CurrentDomain.GetAssemblies();
#else
foreach (var assembly in new[]
{
typeof(string).Assembly, //mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (mscorlib.dll)
typeof(Uri).Assembly, //System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (System.dll)
typeof(System.Linq.Enumerable).Assembly, //System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (System.Core.dll)
typeof(System.Net.WebRequest).Assembly, //System.Net, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (System.Net.dll)
typeof(System.Windows.Application).Assembly //System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e (System.Windows.dll)
})
{
yield return assembly;
}
foreach (var part in System.Windows.Deployment.Current.Parts)
{
var resourceStream = System.Windows.Application.GetResourceStream(new Uri(part.Source, UriKind.Relative));
yield return new System.Windows.AssemblyPart().Load(resourceStream.Stream);
}
#endif
}
#endregion
}
(*) V našem případě nemůžeme použít pouze volání metody Type.GetType(typeName, false), protože tato metoda právě potřebuje specifikovat plné jméno typu včetně assembly (assembly-qualified name).
Jak je uvedeno v MSDN dokumentaci, je totiž v případě uvedení pouze jména typu (type name qualified by its namespace), daný typ vrácen pouze z aktuálně běžící assembly nebo z assembly Mscorlib.dll.