Silverlight 2 dynamic assembly loading - Part 2 |
|
In this article:
- Unpacking and loading the assemblies.
- Direct & Deferred Loading
- Download Progress
In part 1 (click to open) :
- Rebuilding the AppManifest.xaml
- (Re)compressing .xap files with 7zip
A little but later then promised, mostly because I kept building more and more functionality. But here is second part of the Dynamic Assembly Loading. Click here for part 1.
In part 1 we rexapped out applications to meet our requirements, now let’s start loading the application, the custom xaml and the referenced assemblies. We start out with the solutions created in part 1, click here to download it.
ReferencedAssemblies.xaml
To reference and handle the data while loading we create a ReferencedAssembly class looking like this:
public enum ReferencedAssemblyStates { None, Loading, Error, Done };
public class ReferencedAssembly
{
public ReferencedAssemblyStates State;
public long ByteSize;
public long ByteSizeLoaded;
public double PercentLoaded;
public string Name;
public Uri Uri;
public EventHandler Loaded;
public Exception Error;
public AssemblyPart AssemblyPart;
public LoadingTypes loadingType = LoadingTypes.Direct;
}
Then we load our custom created ReferencedAssemblies.xaml from the Application Resource Stream, in the project this is done when you access the getter of the ReferencedAssemblies property:
var xmlReader = XmlReader.Create(
Application.GetResourceStream(
new Uri("ReferencedAssemblies.xaml", UriKind.Relative)
).Stream
);
And use the XamlReader to put the data in our class:
while (xmlReader.ReadToFollowing("ReferencedAssembly"))
{
// Read Name & Source and Size
xmlReader.MoveToAttribute("Name");
var name = xmlReader.Value;
xmlReader.MoveToAttribute("Source");
var uri = new Uri(Application.Current.AbsolutePath() + xmlReader.Value, UriKind.Absolute);
xmlReader.MoveToAttribute("ByteSize");
var byteSize = long.Parse(xmlReader.Value);
// Create a new ReferencedAssembly class and set values
var referencedAssembly = new ReferencedAssembly()
{
Name = name,
Uri = uri,
ByteSize = byteSize
};
// Add it to the Dictionary
Current._ReferencedAssemblies.Add(name, referencedAssembly);
}
So now we have a list of assemblies, their xap file and their size. (This is a new addition to the ReXapper not done in Part 1). With this list we can load up all our referenced assemblies.
Direct & Deferred Loading
As you might have notice by looking at the code above, I added 2 kind of loading methods: Direct and Deferred.
I added these 2 types to make it possible to load assemblies on demand. This can be very useful when you are building bigger applications.
App.Xaml.cs
Now lets look at what we have to do in our applications. All other code we did so far is a one of, meaning we can just reference it next time. This piece of code needs to be added to every application we wish to use this type of assembly loading.
By default your app.xaml.cs contains the following to initiate your Page:
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new Page();
}
This should be changed to:
private void Application_Startup(object sender, StartupEventArgs e)
{
AppAssemblyLoader.Current.LoadReferencedAssemblies(
new string[] { "System.Xml.Linq" },
() => this.RootVisual = new Page()
);
}
What we are doing here is loading the referenced assembly System.Xml.Linq and when it is done call the Page creation method.
Because we also have a MyLibrary.dll in our application this will also be loaded, but this happens in the background. I have added a couple of Events to attach to to monitor what is happening:
public static LoadingDoneEventHandler LoadingDone;
public static LoadingDoneEventHandler LoadingStarted;
public static DownloadProgressChangedEventHandler DownloadProgressChanged;
public static AssemblyDownloadProgressEventHandler AssemblyDownloadProgressChanged;
public static AssemblyStateChangedEventHandler AssemblyStateChanged;
If you want to application to start only after every assembly is loaded you just call it like this:
AppAssemblyLoader.Current.LoadReferencedAssemblies(
() => this.RootVisual = new Page()
);
Loading the Assembly
Loading an assembly is pretty straightforward. First we use a WebClient to get a stream to .xap file.
var wc = new WebClient();
wc.OpenReadCompleted += (sender, e) =>
{
LoadAssemblyFromWebResponse(referencedAssembly, e);
};
wc.OpenReadAsync(referencedAssembly.Uri);
Then we take the Result stream and use it load create an AssemblyPart:
private static void LoadAssemblyFromWebResponse(ReferencedAssembly referencedAssembly, OpenReadCompletedEventArgs e)
{
// Load .xap as StreamResource
var xap = new StreamResourceInfo(e.Result, null);
// Get the assembly (.dll) from the .xap StreamResource
var assemblySri = Application.GetResourceStream(xap, new Uri(referencedAssembly.Name + ".dll", UriKind.Relative));
// Load the stream into a new AssemblyPart
var assemblyPart = referencedAssembly.AssemblyPart = new AssemblyPart();
assemblyPart.Load(assemblySri.Stream);
}
Luckily Silverlight takes care of everything else. The assembly is added to the Assembly Pool, and when another part of you application requests the assembly it is automatically referenced.
Managed Download Progress
You have the possibility to get the download progress for the total and for every separate assembly. If you would load everything deferred, this would enable you to make a Managed Code Loader.
WrapUp
The end project contains a lot more code which I won’t talk about here, but if you download the source code you can check it out yourself.
It ended up being a lot more that just the Loader I was planning it to become. But the things that were added, make it very useful for a few other scenario’s as well:
- Easily separate a Silverlight application into different xap files, making it a good base for bigger applications in SL.
- Create a managed loader, which is currently impossible with Silverlight.
I hope to have time in the next weeks, to build some demo applications to show off the possibilities.
You can download the finished source code here:
Robertjan Tuit - DynamicAssemblyLoading - Part 2 - Source Code.zip
Of course if you have any questions, ideas or remarks please let me know!
Stay in the Light!
Robertjan Tuit
Technorati: Silverlight
Categories : Silverlight














 RSS English
 RSS Nederlands





