Hi all.
I actively use MEF for Silverlight. Recently I got an interesting issue: load *.xap files dynamically to silverlight application. DeploymentCatalog can help us to make it work. When we add DeploymentCatalogs to AggregateCatalog, we can use it from AggregateCatalog of our service. Detail info you can get from this link
But when I needed to get access to CLR types from xap assemblies (with reflection), I get in trouble - DeploymentCatalog encapsulates assemblies that has been loaded from xap file.
Of course I could use meta data with MEF`s Export attribute, but in this case I have to know beforehand about types that will be used out of xap file, which severely limits us. However, if we could get back a list of assemblies from DeploymentCatalog that was created from xap file, we were able to fully work through reflection with types.
So, pulling the code of DeploymentCatalog using reflector from MEF assemblies and adding new property Assemblies, which returns a list of assemblies from private property 'assemblies', I got a new class AssemblyDeploymentCatalog, which has DeploymentCatalog functionality with the ability to return the assemblies that were loaded. Use it!
/// <summary> /// Repeats DeploymentCatalog(MEF) functionality with ability to get assemblies from composable parts /// </summary> public class AssemblyDeploymentCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged { private Uri uri; private AggregateCatalog internalAggregateCatalog; private volatile bool disposed; private WebClient webClient; private int state; private IEnumerable<Assembly> assemblies; private readonly object synchHandle; private EventHandler<DownloadProgressChangedEventArgs> DownloadProgressChanged; /// <summary> /// Initializes a new instance of the <see cref="AssemblyDeploymentCatalog"/> class. /// </summary> /// <param name="uriRelative">The uri relative.</param> public AssemblyDeploymentCatalog(string uriRelative) { this.synchHandle = new object(); this.disposed = false; this.state = 0; this.internalAggregateCatalog = new AggregateCatalog(); this.webClient = null; if (string.IsNullOrEmpty(uriRelative)) { throw new ArgumentNullException("uriRelative"); } this.uri = new Uri(uriRelative, UriKind.Relative); } /// <summary> /// Fires on download complete /// </summary> public event EventHandler<AsyncCompletedEventArgs> DownloadCompleted; /// <summary> /// Fires after discovering parts /// </summary> public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed; /// <summary> /// Fires while discovering parts /// </summary> public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing; /// <summary> /// Gets Assemblies from catalog. /// </summary> public IEnumerable<Assembly> Assemblies { get { return this.assemblies; } } /// <summary> /// Gets composable parts. /// </summary> public override IQueryable<ComposablePartDefinition> Parts { get { this.ThrowIfDisposed(); return this.internalAggregateCatalog.Parts; } } /// <summary> /// Gets current WebClient. /// </summary> private WebClient WebClient { get { this.ThrowIfDisposed(); if (this.webClient == null) { Interlocked.CompareExchange(ref this.webClient, new WebClient(), null); } return this.webClient; } } /// <summary> /// Gets current Uri. /// </summary> private Uri Uri { get { this.ThrowIfDisposed(); return this.uri; } } /// <summary> /// Download package by URI asynchronously /// </summary> public void DownloadAsync() { this.ThrowIfDisposed(); if (Interlocked.CompareExchange(ref this.state, 0x7d0, 0) == 0) { this.WebClient.OpenReadCompleted += this.HandleOpenReadCompleted; this.WebClient.DownloadProgressChanged += this.HandleDownloadProgressChanged; this.WebClient.OpenReadAsync(this.Uri, this); } else { this.MutateStateOrThrow(0xbb8, 0x3e8); this.OnDownloadCompleted(new AsyncCompletedEventArgs(null, false, this)); } } /// <summary>Dispose Deployment Catalog</summary> /// <param name="disposing">The disposing.</param> protected override void Dispose(bool disposing) { try { if (disposing && !this.disposed) { AggregateCatalog catalog = null; try { lock (this.synchHandle) { if (!this.disposed) { catalog = this.internalAggregateCatalog; this.internalAggregateCatalog = null; this.disposed = true; } } } finally { if (catalog != null) { catalog.Dispose(); } } } } finally { base.Dispose(disposing); } } /// <summary>Changed event handler</summary> /// <param name="e">Event arguments</param> private void OnChanged(ComposablePartCatalogChangeEventArgs e) { var changed = this.Changed; if (changed != null) { changed(this, e); } } /// <summary>Changing event handler</summary> /// <param name="e">Event arguments</param> private void OnChanging(ComposablePartCatalogChangeEventArgs e) { var changing = this.Changing; if (changing != null) { changing(this, e); } } /// <summary>DownloadCompleted event handler</summary> /// <param name="e">Event arguments</param> private void OnDownloadCompleted(AsyncCompletedEventArgs e) { var downloadCompleted = this.DownloadCompleted; if (downloadCompleted != null) { downloadCompleted(this, e); } } /// <summary>OpenReadCompleted event handler</summary> /// <param name="sender">The event sender.</param> /// <param name="e">Event arguments</param> private void HandleOpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { var error = e.Error; var cancelled = e.Cancelled; if (Interlocked.CompareExchange(ref this.state, 0xbb8, 0x7d0) != 0x7d0) { cancelled = true; } if ((error == null) && !cancelled) { var downloadedStream = e.Result; this.assemblies = PackageUtility.LoadPackagedAssemblies(downloadedStream); this.DiscoverParts(this.assemblies); } this.OnDownloadCompleted(new AsyncCompletedEventArgs(error, cancelled, this)); } /// <summary>DownloadProgressChanged event handler</summary> /// <param name="sender">The event sender.</param> /// <param name="e">Event arguments</param> private void HandleDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { var downloadProgressChanged = this.DownloadProgressChanged; if (downloadProgressChanged != null) { downloadProgressChanged(this, e); } } private void MutateStateOrThrow(int toState, int fromState) { if (Interlocked.CompareExchange(ref this.state, toState, fromState) != fromState) { throw new InvalidOperationException("InvalidOperationException_DeploymentCatalogInvalidStateChange"); } } /// <summary>Throws exception if object is disposed</summary> private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } } /// <summary>Discover all composable parts from package assemblies</summary> /// <param name="assemblies">The assemblies.</param> private void DiscoverParts(IEnumerable<Assembly> assemblies) { this.ThrowIfDisposed(); var addedDefinitions = new List<ComposablePartDefinition>(); var dictionary = new Dictionary<string, ComposablePartCatalog>(); lock (this.synchHandle) { foreach (var assembly in assemblies) { if (!dictionary.ContainsKey(assembly.FullName)) { var catalog = new AssemblyCatalog(assembly); addedDefinitions.AddRange(catalog.Parts); dictionary.Add(assembly.FullName, catalog); } } } using (var composition = new AtomicComposition()) { var args = new ComposablePartCatalogChangeEventArgs(addedDefinitions, Enumerable.Empty<ComposablePartDefinition>(), composition); this.OnChanging(args); lock (this.synchHandle) { foreach (var pair in dictionary) { this.internalAggregateCatalog.Catalogs.Add(pair.Value); } } composition.Complete(); } var e = new ComposablePartCatalogChangeEventArgs(addedDefinitions, Enumerable.Empty<ComposablePartDefinition>(), null); this.OnChanged(e); } }
Комментариев нет:
Отправить комментарий